package com.shxzz.easy12306.services.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.shxzz.easy12306.framework.starter.cache.StringRedisTemplateProxy;
import com.shxzz.easy12306.framework.starter.common.dto.user.PassengerActualRespDTO;
import com.shxzz.easy12306.framework.starter.convention.exceptions.ServiceException;
import com.shxzz.easy12306.framework.starter.user.core.UserContext;
import com.shxzz.easy12306.services.user.common.constant.RedisKeyConstant;
import com.shxzz.easy12306.services.user.dao.entity.PassengerDO;
import com.shxzz.easy12306.services.user.dao.mapper.PassengerMapper;
import com.shxzz.easy12306.services.user.dto.req.PassengerRemoveReqDTO;
import com.shxzz.easy12306.services.user.dto.req.PassengerReqDTO;
import com.shxzz.easy12306.services.user.dto.resp.PassengerRespDTO;
import com.shxzz.easy12306.services.user.service.PassengerService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * 乘车人列表服务接口实现
 *
 * @author shxzz
 * @create 2024-03-02-20:53
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class PassengerServiceImpl implements PassengerService {

    private final PassengerMapper passengerMapper;

    private final StringRedisTemplateProxy stringRedisTemplateProxy;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void savePassenger(PassengerReqDTO requestParam) {
        String username = UserContext.getUsername();
        PassengerDO passengerDO = BeanUtil.toBean(requestParam, PassengerDO.class);
        passengerDO.setUsername(username);
        passengerDO.setCreateDate(LocalDateTime.now());
        int insert = passengerMapper.insert(passengerDO);
        if (!SqlHelper.retBool(insert)) {
            log.error("[{}] 乘车人添加失败,乘车人信息:{}", username, JSON.toJSONString(requestParam));
            throw new ServiceException("保存乘车人失败");
        }
        delUserPassengerCache(username);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updatePassenger(PassengerReqDTO requestParam) {
        String username = UserContext.getUsername();
        PassengerDO passengerDO = BeanUtil.toBean(requestParam, PassengerDO.class);
        passengerDO.setUsername(username);

        LambdaUpdateWrapper<PassengerDO> updateWrapper = Wrappers.lambdaUpdate(PassengerDO.class)
                .eq(PassengerDO::getUsername, username)
                .eq(PassengerDO::getId, requestParam.getId());
        int update = passengerMapper.update(passengerDO, updateWrapper);
        if (!SqlHelper.retBool(update)) {
            log.error("[{}] 乘车人更新失败,乘车人信息:{}", username, JSON.toJSONString(requestParam));
            throw new ServiceException("乘车人信息修改失败");
        }
        delUserPassengerCache(username);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removePassenger(PassengerRemoveReqDTO requestParam) {
        String username = UserContext.getUsername();
        LambdaQueryWrapper<PassengerDO> queryWrapper = Wrappers.lambdaQuery(PassengerDO.class)
                .eq(PassengerDO::getUsername, username)
                .eq(PassengerDO::getId, requestParam.getId());

        int delete = passengerMapper.delete(queryWrapper);
        if (!SqlHelper.retBool(delete)) {
            log.error("[{}] 乘车人删除失败,乘车人信息:{}", username, JSON.toJSONString(requestParam));
            throw new ServiceException("乘车人信息删除失败");
        }
        delUserPassengerCache(username);
    }

    @Override
    public List<PassengerRespDTO> listPassengerQueryByUsername(String username) {
        String actualUserPassengerListStr = safeGetActualUserPassengerListStr(username);
        return Optional.ofNullable(actualUserPassengerListStr)
                .map(each -> JSON.parseArray(each, PassengerDO.class))
                .map(each -> BeanUtil.copyToList(each, PassengerRespDTO.class))
                .orElse(new ArrayList<>());
    }

    @Override
    public List<PassengerActualRespDTO> listPassengerQueryByIds(String username, List<Long> ids) {
        List<PassengerRespDTO> passengerRespDTOList = listPassengerQueryByUsername(username);
        return passengerRespDTOList.stream()
                .filter(each -> ids.contains(each.getId()))
                .map(each -> BeanUtil.toBean(each, PassengerActualRespDTO.class))
                .toList();
    }

    private String safeGetActualUserPassengerListStr(String username) {
        return stringRedisTemplateProxy
                .safeGet(RedisKeyConstant.USER_PASSENGER_LIST_PREFIX + username,
                        String.class,
                        () -> {
                            LambdaQueryWrapper<PassengerDO> queryWrapper = Wrappers.lambdaQuery(PassengerDO.class)
                                    .eq(PassengerDO::getUsername, username);
                            List<PassengerDO> passengerDOList = passengerMapper.selectList(queryWrapper);
                            return JSON.toJSONString(passengerDOList);
                        },
                        1,
                        TimeUnit.DAYS
                );
    }

    private void delUserPassengerCache(String username) {
        stringRedisTemplateProxy.delete(RedisKeyConstant.USER_PASSENGER_LIST_PREFIX + username);
    }
}
